﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace ListItemEditor
{
    public class ListDataProviderWebSvc : IListDataProvider
    {
        #region variables
        private static Dictionary<string, DataTable> _lookupTableMap = new Dictionary<string, DataTable>();
        private static Dictionary<string, Dictionary<string, int>> _webUserMap = new Dictionary<string, Dictionary<string, int>>();
        #endregion

        #region IListDataProvider Members

        public bool IsDocumentLibrary(GridViewDataSourceSettings settings)
        {
            ListData listData = WscHelper.Current.GetListData (settings);
            return listData != null ? listData.IsDocLib : false;
        }

        public List<string> GetListFields(GridViewDataSourceSettings settings)
        {
            ListData listData = WscHelper.Current.GetListData(settings);
            return listData != null ? listData.Fields.Select(f => f.Name).ToList() : new List<string>();
        }

        public List<string> GetListViews(GridViewDataSourceSettings settings)
        {
            ListData listData = WscHelper.Current.GetListData(settings);
            return listData != null ? listData.Views.Select(v => v.Name).ToList() : new List<string>();
        }

        public string GetListUrl(GridViewDataSourceSettings settings)
        {
            ListData listData = WscHelper.Current.GetListData(settings);
            if (listData == null) return string.Empty;
            Uri uri = new Uri(settings.WebUrl);
            return uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped).TrimEnd('/') + "/" + listData.RootFolder.TrimStart('/');
        }

        public bool Explore(GridViewDataSourceSettings settings, ExploreType exploreType, DataRow row)
        {
            string url;
            switch (exploreType)
            {
                case ExploreType.Web:
                    url = settings.WebUrl; break;
                case ExploreType.Folder:
                    url = this.GetListUrl(settings);
                    if (!string.IsNullOrEmpty(settings.RootFolder))
                        url = url.TrimEnd('/') + "/" + Utility.GetFolderListRelativePath(url, settings.RootFolder).Trim('/');
                    break;
                default:
                    url = this.GetListUrl(settings); break;
            }
            return Utility.Explore(url, exploreType, row);
        }

        public CheckOutStatus GetCheckOutStatusFromDataRow(GridViewDataSourceSettings settings, DataRow row)
        {
            // the faster way of getting the checkout status
            if (!row.Table.Columns.Contains("CheckoutUser") || !row.Table.Columns.Contains("_Level")) return CheckOutStatus.None;
            string user = row["CheckoutUser"].ToString();
            if (string.IsNullOrEmpty(user)) return CheckOutStatus.None;

            int level;
            if (!int.TryParse(row["_Level"].ToString(), out level)) return CheckOutStatus.CheckedOutCurrentUser;
            return level == 255 ? CheckOutStatus.CheckedOutCurrentUser : CheckOutStatus.CheckedOutOtherUser;
            
        }

        public ModerationStatus GetModerationStatusFromDataRow(GridViewDataSourceSettings settings, DataRow row)
        {
            if (!row.Table.Columns.Contains("_ModerationStatus")) return ModerationStatus.Approved;
            string strVal = row["_ModerationStatus"].ToString();
            if (string.IsNullOrEmpty(strVal)) return ModerationStatus.Approved;

            int intVal;
            if (!int.TryParse(strVal, out intVal)) return ModerationStatus.Approved;
            if (intVal < 0 || intVal > 4) return ModerationStatus.Approved;

            return (ModerationStatus)intVal;
        }

        public List<SpecialFieldData> GetSpecialFieldData(GridViewDataSourceSettings settings, List<string> columnNames, bool fetchLookupData)
        {
            List<SpecialFieldData> datas = new List<SpecialFieldData>();
            ListData listData = WscHelper.Current.GetListData(settings);
            Dictionary<string, FieldData> fieldMap = listData.Fields.ToDictionary(f => f.Name);

            foreach (string columnName in columnNames)
            {
                if (!fieldMap.ContainsKey(columnName)) continue;

                FieldData field = fieldMap[columnName];
                if (Utility.UIReadonlyFields.Contains(columnName)) continue;

                SpecialFieldData data = CheckIsLookupField(settings, listData, field, fetchLookupData);
                if (data != null) { datas.Add(data); continue; }

                data = CheckIsLinkField(listData, field);
                if (data != null) { datas.Add(data); continue; }
            }

            return datas;
        }

        public List<string> GetListNamesFromWeb(GridViewDataSourceSettings settings)
        {
            return WscHelper.Current.GetWebListsTitles(settings);
        }

        public void ModifyView(GridViewDataSourceSettings settings, ViewData oldViewData, ViewData newViewData)
        {
            WscHelper.Current.CreateModifyView(settings, oldViewData, newViewData);
        }

        public ViewData GetViewData(GridViewDataSourceSettings settings, string viewName)
        {
            ListData list = WscHelper.Current.GetListData(settings);
            ListData.ViewData view = list.Views.FirstOrDefault(v => string.Compare (v.Name, viewName, false) == 0);
            if (view != null) return WscHelper.Current.GetViewData(settings, view.ID);
            return null;
        }

        #endregion

        #region private

        private SpecialFieldData CheckIsLookupField(GridViewDataSourceSettings settings, ListData list, FieldData field, bool fetchLookupData)
        {
            if (field.FieldType != FieldType.Lookup && field.FieldType != FieldType.LookupMulti && field.FieldType != FieldType.User && field.FieldType != FieldType.UserMulti) return null;

            string showField = field.LookupField;
            string lookupListName = field.LookupList;
            bool isUserField = field.FieldType == FieldType.User || field.FieldType == FieldType.UserMulti;

            Guid listID = Guid.Empty;
            if (!isUserField)
            {
                if (lookupListName.IndexOf("-") < 0) return null;
                try { listID = new Guid(field.LookupList); } catch { return null; }
            }
            else if (string.IsNullOrEmpty(showField)) showField = "ImnName";

            FieldDisplayType displayType = field.FieldType == FieldType.UserMulti || field.FieldType == FieldType.LookupMulti ? FieldDisplayType.MultiSelect : FieldDisplayType.DropDown;
            DataTable table = null;
            if (fetchLookupData)
            {
                string mapKey = settings.WebUrl.TrimEnd('/') + "%%" + lookupListName + "%%" + showField;
                if (_lookupTableMap.ContainsKey(mapKey)) table = _lookupTableMap[mapKey];
                else
                {
                    // NOTE - we only support here lookups with lookup lists in the same web
                    try
                    {
                        GridViewDataSourceSettings lookupSettings = settings.Clone();
                        lookupSettings.ListName = isUserField ? lookupListName : listID.ToString();
                        // force recursive all
                        lookupSettings.ViewScope = ViewScope.RecursiveAll;
                        // force nil root folder
                        lookupSettings.RootFolder = null;

                        ListData lookupList = WscHelper.Current.GetListData(lookupSettings);

                        lookupSettings.ViewFields = new List<string>() { "ID" };
                        if (showField != "ID") lookupSettings.ViewFields.Add(showField);

                        lookupSettings.Query = string.Format("<OrderBy><FieldRef Name='{0}' /></OrderBy>", showField);
                        table = WscHelper.Current.GetListItemData(lookupSettings, lookupList, Guid.Empty, false);
                    }
                    catch { return null; }

                    if (table == null || !table.Columns.Contains(showField)) return null;
                    table.Columns.Add(new DataColumn("SID", typeof(string)));
                    foreach (DataRow row in table.Rows) row["SID"] = row["ID"].ToString() + ";#" + row[showField].ToString();
                    _lookupTableMap[mapKey] = table;
                }
            }
            return new SpecialFieldData() { FieldName = field.Name, DataTable = table, DisplayFieldName = showField, FieldDisplayType = displayType };
        }

        private SpecialFieldData CheckIsLinkField(ListData list, FieldData field)
        {
            string linkFieldName = list.IsDocLib ? "FileLeafRef" : "Title";
            if (field.Name.Equals(linkFieldName)) return new SpecialFieldData() { FieldName = field.Name, DataTable = null, DisplayFieldName = null, FieldDisplayType = FieldDisplayType.Link };
            return null;
        }

        #endregion
    }
}